#include "stdafx.h"
#include "audiowm.h"
#include "audiodef.h"

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

class WMPLAYERINFO : public XAUDIOINFO
{
public:
	WAVEHDR		WaveHdr[DEFAULT_MAXQUEUE_SIZE];
	HWAVEOUT	hWaveOut;
	BYTE*		pBufferPool;
	int			nCurrHdr;
	int			nBufferLength;
	LPVOID		pG723Decoder;
};

CAudioWM::CAudioWM()
{
	hWindow		= NULL;
	PacketSize	= 0;
	m_waveformat = tblWaveFormat[DEFAULT_PCM_FORMAT];
}

CAudioWM::~CAudioWM()
{

}

HRESULT CAudioWM::InitializeAudio( HWND hWnd )
{	
	hWindow = hWnd;

	return S_OK;
}

void CAudioWM::FinalizeAudio( )
{

}


XAUDIOINFO *CAudioWM::GetPlayerInfo( )
{
	WMPLAYERINFO *wpi = new WMPLAYERINFO;
	if( wpi )
	{
		ZeroMemory( wpi, sizeof(WMPLAYERINFO) );
		wpi->hNotificationEvent = CreateEvent(NULL,FALSE,FALSE,NULL);
	}
	return (XAUDIOINFO*)wpi;
}

void CAudioWM::ReleasePlayerInfo( XAUDIOINFO *pai )
{
	WMPLAYERINFO *ppi = (WMPLAYERINFO*) pai;
	if( ppi->hNotificationEvent )
	{
		CloseHandle(ppi->hNotificationEvent);
	}
	if( ppi ) 
	{
		delete ppi;
	}
	ppi = NULL;
}

HRESULT CAudioWM::InitializePlayer( XAUDIOINFO *xai )
{   
	WMPLAYERINFO *wpi = (WMPLAYERINFO*)xai;
	MMRESULT res;
	WAVEHDR *pHdr=0;
	int i;

	m_waveformat = tblWaveFormat[wpi->nSampleFormat];

	//wpi->hNotificationEvent = CreateEvent( NULL, FALSE, TRUE, NULL );

	res = waveOutOpen( &wpi->hWaveOut,
		WAVE_MAPPER,
		&m_waveformat,
		(DWORD)wpi->hNotificationEvent,
		(DWORD)wpi,
		CALLBACK_EVENT );

	if( res!=MMSYSERR_NOERROR )
		goto WMINITPLAYER_ERROR;
#if defined(_OLD_VERSION_)
	switch( wpi->nCodec )
	{
	case AUDIO_PCM:
		wpi->nBufferLength = XAudioPacketSize;
		break;
	case AUDIO_ADPCM:
		wpi->nBufferLength = XAudioPacketSize<<2; // for 4:1 adpcm
		break;
	case AUDIO_G723:
		wpi->pG723Obj = g723_decoder_alloc( );
		wpi->nBufferLength = G723_RawBlockBytes; // for 20:1
		break;
	case AUDIO_MULAW:
//		wpi->pG723Obj = g711_decoder_alloc(XAudioPacketSize );
		wpi->nBufferLength = XAudioPacketSize << 1;
		break;
	case AUDIO_ALAW:
//		wpi->pG723Obj = g711_decoder_alloc(XAudioPacketSize );
		wpi->nBufferLength = XAudioPacketSize << 1;
		break;
	}
#else
	wpi->nBufferLength = PacketSize + 128;//wpi->nBufferLength = DEFAULT_PACKET_SIZE;
#endif
	wpi->nCurrHdr = 0;
	wpi->pBufferPool = new BYTE[wpi->nBufferLength*DEFAULT_MAXQUEUE_SIZE];
	if( !wpi->pBufferPool )
	{
		TRACE(_T("can't allocate memory buffer for capture"));
		return S_FALSE;
	}

	pHdr = wpi->WaveHdr;
	for( i=0; i<DEFAULT_MAXQUEUE_SIZE; i++ )
	{
		pHdr->dwBufferLength = wpi->nBufferLength;
		pHdr->lpData = (char*)(wpi->pBufferPool + i*wpi->nBufferLength);
		pHdr->dwFlags = 0;
		res = waveOutPrepareHeader( wpi->hWaveOut, pHdr, sizeof(WAVEHDR) );
		if( res!=MMSYSERR_NOERROR )
			goto WMINITPLAYER_ERROR;
		pHdr++;
	}

	return S_OK;
WMINITPLAYER_ERROR:
	switch( res )
	{
	case MMSYSERR_NOERROR:
		return S_OK;
	case MMSYSERR_ALLOCATED:
		TRACE(_T("play resource is already allocated"));
		return S_FALSE;
	case MMSYSERR_BADDEVICEID:
		TRACE(_T("bad play device"));
		return S_FALSE;
	case MMSYSERR_NODRIVER:
		TRACE(_T("no play device diver exists"));
		return S_FALSE;
	case MMSYSERR_NOMEM:
		TRACE(_T("unable allocate memory or lock for play"));
		return S_FALSE;
	case WAVERR_SYNC:
		TRACE(_T("play sync error"));
		return S_FALSE;
	case WAVERR_BADFORMAT:
		TRACE(_T("unsupported wave format for play"));
		return S_FALSE;
	default:
		TRACE(_T("unknown eror while initializing play device"));
		return S_FALSE;
	}

}

HRESULT CAudioWM::StartPlayer( XAUDIOINFO *xai )
{
	WMPLAYERINFO *wpi = (WMPLAYERINFO*)xai;
	MMRESULT res = waveOutRestart( wpi->hWaveOut );
	if( res!=MMSYSERR_NOERROR )
	{
		switch( res )
		{
		case MMSYSERR_INVALHANDLE:
			TRACE(_T("invalid play handle"));
			return S_FALSE;
		case MMSYSERR_NODRIVER:
			TRACE(_T("no play device diver exists"));
			return S_FALSE;
		case MMSYSERR_NOMEM:
			TRACE(_T("unable allocate memory or lock for play"));
			return S_FALSE;
		case MMSYSERR_NOTSUPPORTED:
			TRACE(_T("play device don't support pause"));
			return S_FALSE;
		default:
			TRACE(_T("unknown eror while initializing play device"));
			return S_FALSE;
		}
	}
	return S_OK;
}

HRESULT CAudioWM::StopPlayer( XAUDIOINFO *pai )
{
	WMPLAYERINFO *wpi = (WMPLAYERINFO*)pai;
	MMRESULT res = waveOutPause( wpi->hWaveOut );
	if( res!=MMSYSERR_NOERROR )
	{
		switch( res )
		{
		case MMSYSERR_INVALHANDLE:
			TRACE(_T("invalid play handle"));
			return S_FALSE;
		case MMSYSERR_NODRIVER:
			TRACE(_T("no play device diver exists"));
			return S_FALSE;
		case MMSYSERR_NOMEM:
			TRACE(_T("unable allocate memory or lock for play"));
			return S_FALSE;
		case MMSYSERR_NOTSUPPORTED:
			TRACE(_T("play device don't support pause"));
			return S_FALSE;
		default:
			TRACE(_T("unknown eror while initializing play device"));
			return S_FALSE;
		}
	}
	return S_OK;
}

HRESULT CAudioWM::PlayerSetVolume( XAUDIOINFO *pai, DWORD vol )
{
	WMPLAYERINFO *wpi = (WMPLAYERINFO*)pai;
	WORD step = 0x0ffff / 100;
	WORD single = (WORD)vol * step;
	DWORD dwVol = MAKELONG( single, single );
	MMRESULT res = waveOutSetVolume( wpi->hWaveOut, dwVol );
	switch( res )
	{
	case MMSYSERR_NOERROR:
		return S_OK;
	case MMSYSERR_INVALHANDLE:
		TRACE(_T("invalid play handle"));
		return S_FALSE;
	case MMSYSERR_NODRIVER:
		TRACE(_T("no play device diver exists"));
		return S_FALSE;
	case MMSYSERR_NOMEM:
		TRACE(_T("unable allocate memory or lock for play"));
		return S_FALSE;
	case MMSYSERR_NOTSUPPORTED:
		TRACE(_T("play device don't support pause"));
		return S_FALSE;
	default:
		TRACE(_T("unknown eror while initializing capture device"));
		return S_FALSE;
	}
	return S_FALSE;
}

HRESULT CAudioWM::PlayerGetVolume( XAUDIOINFO *pai, DWORD *vol )
{
	WMPLAYERINFO *wpi = (WMPLAYERINFO*)pai;
	MMRESULT res = waveOutGetVolume( wpi->hWaveOut, vol );
	switch( res )
	{
	case MMSYSERR_NOERROR:
		return S_OK;
	case MMSYSERR_INVALHANDLE:
		TRACE(_T("invalid play handle"));
		return S_FALSE;
	case MMSYSERR_NODRIVER:
		TRACE(_T("no play device diver exists"));
		return S_FALSE;
	case MMSYSERR_NOMEM:
		TRACE(_T("unable allocate memory or lock for play"));
		return S_FALSE;
	case MMSYSERR_NOTSUPPORTED:
		TRACE(_T("play device don't support pause"));
		return S_FALSE;
	default:
		TRACE(_T("unknown eror while initializing capture device"));
		return S_FALSE;
	}
	return S_FALSE;
}

HRESULT CAudioWM::PlayerWritePacket( XAUDIOINFO *pai, XAUDIOPACKET *pkt )
{
	WMPLAYERINFO *wpi = (WMPLAYERINFO*)pai;
	MMRESULT res;
	WORD	wCodec;
	WAVEHDR *pHdr = wpi->WaveHdr + wpi->nCurrHdr;

    if( !wpi )
        return S_FALSE;
	
	wCodec = wpi->nCodec; // should be equal to HIWORD( pkt->fmt );
	
	if( pkt->length==0 ) // blank data
	{
		return S_OK;
	}

	if( pHdr->dwFlags&WHDR_DONE )
	{
		res = waveOutUnprepareHeader( wpi->hWaveOut, pHdr, sizeof(WAVEHDR) );
		if( res!=MMSYSERR_NOERROR )
			goto PLAYPACKET_ERROR;		
	}
	else if( pHdr->dwFlags&WHDR_PREPARED )
		;
	else // buffer not ready
		return S_FALSE;
#if defined(_OLD_VERSION_)
	if( wCodec==AUDIO_PCM )
	{
		pkt->length = MIN( XAudioPacketSize, pkt->length );
		memcpy( pHdr->lpData, pkt->data, pkt->length );
		pHdr->dwBufferLength = pkt->length;
	}
	else if( wCodec==AUDIO_ADPCM )
	{
		pkt->length = MIN( XAudioPacketSize, pkt->length );
		if( IS_STEREO_SAMPLE( wpi->nSampleFormat ) )
			adpcm_decoder_stereo( (char*)pkt->data, (short*)pHdr->lpData, pkt->length, &wpi->AdpcmState );
		else
			adpcm_decoder_mono( (char*)pkt->data, (short*)pHdr->lpData, pkt->length, &wpi->AdpcmState );

		pHdr->dwBufferLength = pkt->length<<2;
	}
	else if( wCodec==AUDIO_G723 )
	{
		pHdr->dwBufferLength = g723_decode( wpi->pG723Decoder,
			(char*)pkt->data, pkt->length,
			(short*)pHdr->lpData, pHdr->dwBufferLength  );
		if( pHdr->dwBufferLength > G723_RawBlockBytes )
			return FALSE;
	}
	else if( wCodec==AUDIO_MULAW )
	{
		pkt->length = MIN( XAudioPacketSize, pkt->length );
		memcpy( pHdr->lpData, pkt->data, pkt->length );
		pHdr->dwBufferLength = pkt->length;
	}
	else if( wCodec==AUDIO_ALAW )
	{
		pkt->length = MIN( XAudioPacketSize, pkt->length );
		memcpy( pHdr->lpData, pkt->data, pkt->length );
		pHdr->dwBufferLength = pkt->length;
	}	
#else
		
#if 0
		if( wpi->nBufferLength < pkt->length )
			pkt->length = wpi->nBufferLength;

		pkt->length = 900;
		memcpy( pHdr->lpData, pkt->data, pkt->length );
		pHdr->dwBufferLength = pkt->length;
#else
	memcpy( pHdr->lpData, pkt->data, pkt->length );
		pHdr->dwBufferLength = pkt->length;
#endif
#endif
	pHdr->dwFlags = 0;
	res = waveOutPrepareHeader( wpi->hWaveOut, pHdr, sizeof(WAVEHDR) );
	if( res!=MMSYSERR_NOERROR )
		goto PLAYPACKET_ERROR;

	res = waveOutWrite( wpi->hWaveOut, pHdr, sizeof(WAVEHDR) );
	if( res!=MMSYSERR_NOERROR )
		goto PLAYPACKET_ERROR;

	wpi->nCurrHdr = (wpi->nCurrHdr+1)%DEFAULT_MAXQUEUE_SIZE;

PLAYPACKET_ERROR:
	switch( res )
	{
	case MMSYSERR_NOERROR:
		return S_OK;
	case MMSYSERR_INVALHANDLE:
		TRACE(_T("invalid play handle"));
		return S_FALSE;
	case MMSYSERR_NODRIVER:
		TRACE(_T("no play device diver exists"));
		return S_FALSE;
	case MMSYSERR_NOMEM:
		TRACE(_T("unable allocate memory or lock for play"));
		return S_FALSE;
	case MMSYSERR_NOTSUPPORTED:
		TRACE(_T("play device don't support pause"));
		return S_FALSE;
	case WAVERR_UNPREPARED:
		TRACE(_T("play buffer unprepared"));
		return S_FALSE;
	case WAVERR_STILLPLAYING:
		TRACE(_T("play not stopped while closing"));
		return S_FALSE;
	default:
		TRACE(_T("unknown eror while initializing capture device"));
		return S_FALSE;
	}	

	return S_FALSE;
}

void CAudioWM::FinalizePlayer( XAUDIOINFO *xai )
{
	WMPLAYERINFO *wpi = (WMPLAYERINFO*)xai;
	MMRESULT  res;
	int i;

	res = waveOutReset( wpi->hWaveOut );
	if( res!=MMSYSERR_NOERROR )
		goto WMPLAYER_CLEANUP;
	
	for( i=0; i<DEFAULT_MAXQUEUE_SIZE; i++ )
	{
		res = waveOutUnprepareHeader( wpi->hWaveOut, wpi->WaveHdr + i, sizeof(WAVEHDR) );
		if( res!=MMSYSERR_NOERROR )
			goto WMPLAYER_CLEANUP;
	}

	res = waveOutClose( wpi->hWaveOut );
	if( res!=MMSYSERR_NOERROR )
		goto WMPLAYER_CLEANUP;

WMPLAYER_CLEANUP:
	
	if( wpi->hNotificationEvent )
	{
		CloseHandle( wpi->hNotificationEvent );
		wpi->hNotificationEvent = NULL;
	}
#if defined(_OLD_VERSION_)
	if( wpi->nCodec==AUDIO_G723 )
	{
		g723_decoder_free( wpi->pG723Obj );
	}
//	if( wpi->nCodec == AUDIO_MULAW 
//		|| wpi->nCodec == AUDIO_ALAW )
//	{
//		g711_decoder_free(wpi->pG723Obj );
//	}
#endif
	if( wpi->pBufferPool )
	{
		delete[] wpi->pBufferPool;
		wpi->pBufferPool = NULL;
	}

	switch( res )
	{
	case MMSYSERR_NOERROR:
		return;
	case MMSYSERR_INVALHANDLE:
		TRACE(_T("invalid play handle"));
		return;
	case MMSYSERR_NODRIVER:
		TRACE(_T("no play device diver exists"));
		return;
	case MMSYSERR_NOMEM:
		TRACE(_T("unable allocate memory or lock for play"));
		return;
	case MMSYSERR_NOTSUPPORTED:
		TRACE(_T("play device don't support pause"));
		return;
	case WAVERR_STILLPLAYING:
		TRACE(_T("play not stopped while closing"));
		return;
	default:
		TRACE(_T("unknown eror while initializing capture device"));
		return;
	}
}

void CAudioWM::SetPacketSize(int nsize)
{
	PacketSize = nsize;
}
